// notadd装饰器
//---------------------------------------------------------------------
// 必须有一个new方法返回类型T数据,new方法的参数不定
export interface Type<T> extends Function {
    new(...args: any[]): T;
}
//---------------------------------------------------------------------
export class IClassDecorator<T = any, O = any> {
    private _type: Type<T>;
    private _options: O | undefined;
    private _metadataKey: string;
    private _params: any[];
    get options(): O | undefined {
        return this._options;
    }
    set options(o: O | undefined) {
        this._options = o;
    }
    get type() {
        return this._type;
    }
    get metadataKey() {
        return this._metadataKey;
    }
    get parameters() {
        return this._params;
    }
    constructor(type: Type<T>, options: O, metadataKey: string, params: any) {
        this._type = type;
        this._options = options;
        this._metadataKey = metadataKey;
        this._params = params;
    }
}

export interface ClassHanlder<O = any> {
    (item: IClassDecorator<any, O>): void;
}
//---------------------------------------------------------------------
export type TypeProperty = string | symbol;
//---------------------------------------------------------------------
export class IPropertyDecorator<T = any, O = any> {
    private _property: string | symbol;
    private _instance: T;
    private _type: Type<T>;
    private _options: O | undefined;
    private _propertyType: any;
    get property() {
        return this._property;
    }
    get instance() {
        return this._instance;
    }
    get type() {
        return this._type;
    }
    get options(): O | undefined {
        return this._options;
    }
    set options(o: O | undefined) {
        this._options = o;
    }
    get propertyType() {
        return this._propertyType;
    }
    private _metadataKey: string | undefined;
    get metadataKey() {
        return this._metadataKey;
    }
    constructor(
        property: TypeProperty,
        instance: T,
        type: Type<T>,
        options?: O,
        propertyType?: any,
        metadataKey?: string
    ) {
        this._property = property;
        this._instance = instance;
        this._type = type;
        this._options = options;
        this._propertyType = propertyType;
        this._metadataKey = metadataKey;
    }
}

export interface PropertyHandler<O = any> {
    (item: IPropertyDecorator<any, O>): void;
}
//---------------------------------------------------------------------
export class IConstructorDecorator<T = any, O = any>{
    private _type: Type<T>;
    private _options: O | undefined;
    private _parameterIndex: number;
    private _parameterTypes: any[];
    private _parameterType: any;
    get type() {
        return this._type;
    }
    get options(): O | undefined {
        return this._options;
    }
    set options(o: O | undefined) {
        this._options = o;
    }
    get parameterIndex() {
        return this._parameterIndex;
    }
    get parameterType() {
        return this._parameterType || this._parameterTypes[this.parameterIndex]
    }
    private _metadataKey: string;
    get metadataKey() {
        return this._metadataKey;
    }
    constructor(type: Type<T>, parameterIndex: number, options: O, parameterTypes: any[], metadataKey: string) {
        this._type = type;
        this._parameterIndex = parameterIndex;
        this._options = options;
        this._parameterTypes = parameterTypes;
        this._metadataKey = metadataKey;
    }
    setParamterType(type: any) {
        this._parameterType = type;
    }
}
//---------------------------------------------------------------------
export class IParameterDecorator<T = any, O = any> {
    private _instance: T;
    private _type: Type<T>;
    private _property: string | symbol;
    private _parameterIndex: number;
    private _options: O | undefined;
    private _parameterTypes: any[];
    get instance() {
        return this._instance;
    }
    get type() {
        return this._type;
    }
    get property() {
        return this._property;
    }
    get parameterIndex() {
        return this._parameterIndex;
    }
    get options(): O | undefined {
        return this._options;
    }
    set options(o: O | undefined) {
        this._options = o;
    }
    get parameterType() {
        return this._parameterTypes[this.parameterIndex];
    }
    private _metadataKey: string;
    get metadataKey() {
        return this._metadataKey;
    }
    constructor(instance: T, type: Type<T>, property: TypeProperty, parameterIndex: number, options: O, parameterTypes: any[], metadataKey: string) {
        this._instance = instance;
        this._type = type;
        this._property = property;
        this._parameterIndex = parameterIndex;
        this._options = options;
        this._parameterTypes = parameterTypes;
        this._metadataKey = metadataKey;
    }
}

export interface ParameterHandler<O = any> {
    (arg: IConstructorDecorator<any, O> | IParameterDecorator<any, O>): void;
}
//---------------------------------------------------------------------
export class IMethodDecorator<T = any, O = any> {
    private _property: TypeProperty;
    private _instance: T;
    private _type: Type<T>;
    private _descriptor: TypedPropertyDescriptor<any> | undefined;
    private _options: O | undefined;
    private _parameters: Set<IParameterDecorator> = new Set();
    private _returnType: any;
    private _paramTypes: any[];
    get returnType() {
        return this._returnType;
    }
    get paramTypes() {
        return this._paramTypes || [];
    }
    get parameters() {
        return [...this._parameters];
    }
    get options(): O | undefined {
        return this._options;
    }
    set options(o: O | undefined) {
        this._options = o;
    }
    get descriptor() {
        return this._descriptor;
    }
    get type() {
        return this._type;
    }
    get instance() {
        return this._instance;
    }
    get property() {
        return this._property;
    }
    private _metadataKey: string | undefined;
    get metadataKey() {
        return this._metadataKey;
    }
    constructor(
        property: string | symbol,
        instance: T,
        type: Type<T>,
        descriptor: TypedPropertyDescriptor<any> | undefined,
        options: O,
        returnType: any,
        paramTypes: any,
        metadataKey: string | undefined
    ) {
        this._property = property;
        this._instance = instance;
        this._type = type;
        this._descriptor = descriptor;
        this._metadataKey = metadataKey;
        this._options = options;
        this._returnType = returnType;
        this._paramTypes = paramTypes;
    }

    setDescriptor(descriptor: TypedPropertyDescriptor<any> | undefined) {
        this._descriptor = descriptor;
    }

    setReturnType(returnType: any) {
        this._returnType = returnType;
    }

    setParamTypes(paramTypes: any[]) {
        this._paramTypes = paramTypes;
    }

    setOptions(options: O) {
        this._options = options;
    }

    setMetadataKey(key: string | undefined) {
        this._metadataKey = key;
    }

    addParameter(item: IParameterDecorator) {
        this._parameters.add(item);
    }
}

export interface MethodHandler<O = any> {
    (item: IMethodDecorator<any, O>): void;
}
//---------------------------------------------------------------------
export type CallHanlder<O> = ClassHanlder<O> | PropertyHandler<O> | MethodHandler<O> | ParameterHandler<O>;
//---------------------------------------------------------------------
export interface NgerDecorator<O = any> {
    options?: O;
    ngMetadataName: string;
}

export interface NgerClassDecorator<O, T> {
    (opt?: O): ClassDecorator
    new(arg?: T): NgerDecorator<T>;
}
//---------------------------------------------------------------------
import "reflect-metadata"
export const getDesignTargetParams = (target: any) => Reflect.getMetadata('design:paramtypes', target);
//---------------------------------------------------------------------
let _globalAfterHandlers: Map<string, CallHanlder<any>> = new Map();
let _globalBeforeHandlers: Map<string, CallHanlder<any>> = new Map();
export function setGlobalBeforeHandlers(handlers: Map<string, CallHanlder<any>>) {
    _globalBeforeHandlers = handlers;
}
export function setGlobalAfterHandlers(handlers: Map<string, CallHanlder<any>>) {
    _globalAfterHandlers = handlers;
}
export function getGlobalBeforeHanderAndCall(key: string, item: any) {
    const handler = _globalBeforeHandlers.get(key);
    if (handler) handler(item);
}
export function getGlobalAfterHanderAndCall(key: string, item: any) {
    const handler = _globalAfterHandlers.get(key);
    if (handler) handler(item);
}
//---------------------------------------------------------------------

export class INgerDecorator<T = any, O = any> {
    readonly type: Type<T>;
    private _classes: Set<IClassDecorator> = new Set();
    private _properties: Set<IPropertyDecorator> = new Set();
    private _constructors: Set<IConstructorDecorator> = new Set();
    private _methods: Set<IMethodDecorator> = new Set();
    get classes() {
        return [...this._classes];
    }
    get methods() {
        return [...this._methods];
    }
    get properties() {
        return [...this._properties];
    }
    get constructors() {
        return [...this._constructors];
    }
    constructor(type: Type<T>) {
        this.type = type;
    }
    addClass(item: IClassDecorator) {
        this._classes.add(item)
    }
    addProperty(
        item: IPropertyDecorator
    ) {
        this._properties.add(item);
    }
    addConstructor(item: IConstructorDecorator) {
        this._constructors.add(item);
    }
    addMethod(
        item: IMethodDecorator
    ) {
        const method = this.__getMethod(item.property, item.instance, item.type, item.metadataKey);
        method.setDescriptor(item.descriptor);
        method.setReturnType(item.returnType);
        method.setParamTypes(item.paramTypes);
        method.setOptions(item.options);
        method.setMetadataKey(item.metadataKey);
    }
    addMethodParameter(item: IParameterDecorator) {
        const method = this.__getMethod(item.property, item.instance, item.type)
        return method.addParameter(item)
    }
    private __getMethod(property: TypeProperty, instance: T, type: Type<T>, metadataKey?: string): IMethodDecorator {
        let method = [...this._methods].find(it => {
            if (metadataKey && it.metadataKey) {
                return it.property === property && it.metadataKey === metadataKey;
            }
            return it.property === property
        });
        if (method) return method;
        method = new IMethodDecorator(property, instance, type, undefined, undefined, undefined, undefined, undefined)
        this._methods.add(method);
        return method;
    }
}
//---------------------------------------------------------------------
const nger = Symbol.for(`__nger__decorator__`);
export function getINgerDecorator<T = any, O = any>(type: Type<T>): INgerDecorator<T, O> {
    if(!type){
        throw new Error(`get nger decorator error`)
    }
    if (!Reflect.has(type, nger)) {
        const value = new INgerDecorator(type);
        Reflect.defineProperty(type, nger, {
            value
        });
    }
    return Reflect.get(type, nger);
}
//---------------------------------------------------------------------
export class DecoratorStore {
    private _map: Map<string, Set<any>> = new Map();
    /**
     * 设置
     * @param @string metadataKey 
     * @param @Type val 
     */
    set<T = any>(metadataKey: string, val: Type<T>) {
        const allTypes = this.get(metadataKey)
        allTypes.add(val);
        this._map.set(metadataKey, allTypes);
    }
    /**
     * 获取使用某个装饰器的所有类
     * @param @string metadataKey 
     */
    get<T>(metadataKey: string): Set<T> {
        let allTypes = this._map.get(metadataKey);
        if (!allTypes) {
            allTypes = new Set();
        }
        return allTypes;
    }
}
export const clsStore = new DecoratorStore();
//---------------------------------------------------------------------
export function createClassDecorator<O = any, T extends O = O>(
    metadataKey: string,
    beforeHandler?: ClassHanlder<O>,
    afterHandler?: ClassHanlder<O>
): NgerClassDecorator<O, T> {
    function DecoratorFactory(this: any, opts?: O): ClassDecorator {
        if (this instanceof DecoratorFactory) {
            (this as NgerDecorator<T>).options = opts as T;
            return this as any;
        }
        function Decorator(target: any) {
            const type = target;
            let options: any = opts;
            const params = getDesignTargetParams(target) || [];
            const classDecorator = getINgerDecorator(type);
            const item = new IClassDecorator(type, options, metadataKey, params);
            beforeHandler && beforeHandler(item);
            // before 钩子
            getGlobalBeforeHanderAndCall(metadataKey, item);
            classDecorator.addClass(item);
            clsStore.set(metadataKey, type);
            afterHandler && afterHandler(item);
            getGlobalAfterHanderAndCall(metadataKey, item)
        }
        return Decorator;
    }
    DecoratorFactory.prototype.ngMetadataName = metadataKey;
    return DecoratorFactory as any;
}
//---------------------------------------------------------------------
export interface BaseProvider {
    provide: any;
    multi?: boolean;
    noCache?: boolean;
}
export interface TypeProvider extends Type<any> { }
export interface ClassProvider extends BaseProvider {
    useClass: Type<any>;
}
export interface ValueProvider extends BaseProvider {
    useValue: any;
}
export interface ConstructorProvider extends BaseProvider {
    deps?: any[];
}
export interface ExistingProvider extends BaseProvider {
    useExisting: any;
}
export interface FactoryProvider extends BaseProvider {
    useFactory: Function;
    deps?: any[];
}
export type Provider = TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider;
export type Providers = Provider | Providers[];
export interface ModuleWithProviders<T = any> {
    ngModule: Type<T>;
    providers: Providers[];
}
//---------------------------------------------------------------------
export const ModuleMetadataKey = `ModuleMetadataKey`;
export interface ModuleOptions {
  providers?: Providers[];
  imports?: Array<Type<any> | ModuleWithProviders<any>>;
  controllers?: Type<any>[];
}
export const ModuleTest = createClassDecorator<ModuleOptions>(ModuleMetadataKey);
//---------------------------------------------------------------------
import { Get } from '@notadd/http'
import { MAIN_PATH, PLATFORM_NAME, PLATFORM_TITLE,Controller,Router,Module } from '@notadd/core';
@Controller()
export class HttpController {
    // constructor(private webRTCNVRService: WebRtcNVRService) {}
    constructor() { };

    @Get("/")
    async version1(): Promise<string> {
        console.log('GET /');
        return "OK";
    }
}
//---------------------------------------------------------------------
@Module({
    imports: [],
    controllers: [
        HttpController,
    ],
})
export class HttpApiModule {}
//---------------------------------------------------------------------
@Module({
    imports:[
        HttpApiModule
    ]
})
export class ApiModule { }
//---------------------------------------------------------------------
import { platformNode } from '@notadd/platform-node';

platformNode([
    {
        provide: MAIN_PATH,
        useValue: __filename,
    },
    {
        provide: PLATFORM_NAME,
        useValue: 'webrtc-box',
    },
    {
        provide: PLATFORM_TITLE,
        useValue: 'webrtc box',
    },
])
    .bootstrapModule(ApiModule)
    .then(async (res)=>{
        
        const router = res.injector.get(Router);
        console.log("启动成功");
    }).catch(async (err)=>{
        console.log(err);
    });